
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Map.Entry;

public class GUIBasedModel {

	static UtmRwr_Model utm = new UtmRwr_Model(0, 0, 0);
	
	float[][] calGMRating = new float[utm.G][utm.M];
	float[] calGMAvgRating = new float[utm.G];
	float[][] sGG = new float[utm.G][utm.G];
	float[][] preGMRating = new float[utm.G][utm.M];
	
	float[] calUMAvgRating = new float[utm.U];
	float[][] sUU = new float[utm.U][utm.U];
	float[][] preUMRating = new float[utm.U][utm.M];
	
	float[][] sMM = new float[utm.M][utm.M];
	
	int S;
	float[][] ss;
	int[][] ssIndex;

	public static void main(String[] args) throws Exception {
		utm.readDocs("");
		GUIBasedModel model = new GUIBasedModel();
		
	// model.execute(UtmRwr_Model.Policy.avg);
//		for(UtmRwr_Model.Policy tmp : UtmRwr_Model.Policy.values())
//		{
//			model.execute(tmp);	
//		}
//		model.execute(UtmRwr_Model.Policy.avg);		
		model.execute(UtmRwr_Model.Policy.lm);  // 选策路
		
		
		
	}
	
	public void execute(UtmRwr_Model.Policy policy){
		System.out.println(policy+" policy:");
		initializeMatrix();
		
		utm.calculateTestGMRating(policy);
		calculateGMRating(policy);
		calculateUMAvgRating();
		
//	groupBasedModel(policy);
		
//		userBasedModel(policy);
		
  	itemBasedPrediction(policy);

//		itemBasedModel(policy);
		
		try {
			maeAucPcsMapRecallUser(UtmRwr_Model.Model.gui, policy);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public void initializeMatrix(){
		for(int i=0;i<utm.G;i++){
			calGMAvgRating[i] = -1;
			for(int j=0;j<utm.M;j++){
				calGMRating[i][j] = -1;
				preGMRating[i][j] = -1;
			}
			for(int j=0;j<utm.G;j++){
				sGG[i][j] = -1;
			}
		}
		for(int i=0;i<utm.U;i++){
			calUMAvgRating[i] = -1;
			for(int j=0;j<utm.M;j++){
				preUMRating[i][j] = -1;
			}
			for(int j=0;j<utm.U;j++){
				sUU[i][j] = -1;
			}
		}
		for(int i=0;i<utm.M;i++){
			for(int j=0;j<utm.M;j++){
				sMM[i][j] = -1;
			}
		}
	}

	//average rating of all movies by user
	public void calculateUMAvgRating(){
		for (int uid : utm.userListTrain) {
			float sum = 0, num = 0;
			for (Movie movie : utm.allMovies) {
				if (movie.users.containsKey(uid)) {
					sum += movie.users.get(uid);
					num++;
				}
			}
			calUMAvgRating[utm.userListTrain.indexOf(uid)] = sum / num;// ÿ���û����ٶ�1��movie���˷֣�num!=0����NaN
		}
		System.out.println("calUMAvgRating completed!");
	}
	
	/**
	 * calculate calGMRating[][] and calGMAvgRating[]
	 * @param policy
	 */
	public void calculateGMRating(UtmRwr_Model.Policy policy){

		for (int g = 0; g < utm.G; g++) {
			float sumOfNum = 0;
			for (int n : utm.allGroups[g].users.values()) {
				sumOfNum += n;
			}
			for (int m = 0; m < utm.M; m++) {
				float cGMRating = (policy == UtmRwr_Model.Policy.lm) ? Integer.MAX_VALUE : -1;
				for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
					if (!utm.allMovies[m].users.containsKey(user.getKey()))
						continue;
					switch (policy) {
					case wtd:
						cGMRating += user.getValue() / sumOfNum
								* utm.allMovies[m].users.get(user.getKey());
						break;
					case lm:
						cGMRating = Math.min(cGMRating,
								utm.allMovies[m].users.get(user.getKey()));
						break;
					case avg:
						cGMRating += utm.allMovies[m].users.get(user.getKey());
						break;
					}
				}
				if (cGMRating == Integer.MAX_VALUE)
					cGMRating = -1;
				if (cGMRating != -1) {
					if (policy != UtmRwr_Model.Policy.lm)
						cGMRating++;
					if (policy == UtmRwr_Model.Policy.avg)
						cGMRating /= utm.allGroups[g].users.size();
//					if(utm.allMovies[m].mid==1 || utm.allMovies[m].mid==2){
//						System.out.println("calGMRating!=-1{gid,mid}:"+utm.allGroups[g].gid+","+utm.allMovies[m].mid);
//					}
				}
				calGMRating[g][m] = cGMRating;
				for (int i = 0; i < calGMRating[g].length; i++) {
					if (calGMRating[g][i] != -1)
						calGMAvgRating[g] += calGMRating[g][i];
				}
				calGMAvgRating[g] /= sumOfNum;
			}
		}
	}
	// what?
	public void print(float[][] matrix){
		for(float[] row:matrix){
			for(float e:row)
				System.out.print(e+",");
			System.out.println();
		}
	}
	public void print(float[] array){
		for(float e:array)
			System.out.print(e+",");
	}
	
	public void itemBasedModel(UtmRwr_Model.Policy policy){
		System.out.println("item based model");
		//Similarity between movies
		for (int m1 = 0; m1 < utm.M; m1++) {
			sMM[m1][m1] = 1;
			for (int m2 = m1 + 1; m2 < utm.M; m2++) {
				float fz = 0, fm1 = 0, fm2 = 0;
				int numOfCommonGroups = 0;
				for (int g=0;g<utm.G;g++) {
					if (calGMRating[g][m1] ==-1	|| calGMRating[g][m2] ==-1)
						continue;
					numOfCommonGroups++;
					fz += (calGMRating[g][m1] - calGMAvgRating[g]) * (calGMRating[g][m2] - calGMAvgRating[g]);
					fm1 += Math.pow(calGMRating[g][m1] - calGMAvgRating[g], 2);
					fm2 += Math.pow(calGMRating[g][m2] - calGMAvgRating[g], 2);
				}
				sMM[m1][m2] = (float)((numOfCommonGroups < 3) ? 0 : fz/(Math.sqrt(fm1) * Math.sqrt(fm2)));
				sMM[m2][m1] = sMM[m1][m2];
			}
		}
		System.out.println("sMM completed!");
		
		//3.13 update
		S = utm.M;
		ss = new float[S][];
		ssIndex = new int[S][];
		for (int i = 0; i < S; i++) {
			ss[i] = new float[utm.M];
			ssIndex[i] = new int[utm.M];
			for (int m = 0; m < utm.M; m++) {
				int index = utm.findIndexOfLargest(sMM[m], 0, utm.M);
				ss[i][m] = sMM[m][index];
				ssIndex[i][m] = index;
				sMM[m][index] = -1;
			}
		}
		
		//predicting ratings of movies rated by group
		for (int g = 0; g < utm.G; g++) {
			float fz = 0, fm = 0;
			for (int m1 = 0; m1 < utm.M; m1++) {
				for (int i = 0; i < S; i++) {
					if (ss[i][m1] == 0 || calGMRating[g][ssIndex[i][m1]] == -1)
						continue;
					fz += ss[i][m1] * calGMRating[g][ssIndex[i][m1]];
					fm += ss[i][m1];
				}
				preGMRating[g][m1] = fz / fm;
			}
		}
		
//		try {
//			UtmRwr_Model.matrixToFile(ss, "./GUI_results/"+UtmRwr_Model.Model.item_mod+"/"+policy+"/ss_result.csv");
//			UtmRwr_Model.matrixToFile(calGMRating,"./GUI_results/"+UtmRwr_Model.Model.item_mod+"/"+policy+"/calGMRating_result.csv");
//			UtmRwr_Model.matrixToFile(preGMRating,"./GUI_results/"+UtmRwr_Model.Model.item_mod+"/"+policy+"/preGMRating_result.csv");
//		} catch (Exception e) {
//			System.out.println("error in matrixToFile");
//			e.printStackTrace();
//		} 
	}
	
	public void itemBasedPrediction(UtmRwr_Model.Policy policy){
		System.out.println("item based prediction");
		//Similarity between movies
		for(int m1 = 0;m1<utm.M;m1++){
			sMM[m1][m1] = 1;
			for(int m2=m1+1;m2<utm.M;m2++){
				float fz = 0,fm1 = 0,fm2 = 0;
				int numOfCommonUsers=0;
				for(int uid:utm.userListTrain){
					if(!utm.allMovies[m1].users.containsKey(uid) || 
					   !utm.allMovies[m2].users.containsKey(uid))
						continue;
					numOfCommonUsers++;
					fz += (utm.allMovies[m1].users.get(uid) - calUMAvgRating[utm.userListTrain.indexOf(uid)])
							*(utm.allMovies[m2].users.get(uid) - calUMAvgRating[utm.userListTrain.indexOf(uid)]);
					fm1 += Math.pow(utm.allMovies[m1].users.get(uid) - calUMAvgRating[utm.userListTrain.indexOf(uid)], 2);
					fm2 += Math.pow(utm.allMovies[m2].users.get(uid) - calUMAvgRating[utm.userListTrain.indexOf(uid)], 2);
				}
				sMM[m1][m2] = (float)((numOfCommonUsers < 3) ? 0 : fz / (Math.sqrt(fm1) * Math.sqrt(fm2)));
				sMM[m2][m1] = sMM[m1][m2];
			}
		}
		System.out.println("sMM completed!");
		
		//3.13 update
		S = utm.M;
		ss = new float[S][];
		ssIndex = new int[S][];
		for (int i = 0; i < S; i++) {
			ss[i] = new float[utm.M];
			ssIndex[i] = new int[utm.M];
			for (int m = 0; m < utm.M; m++) {
				int index = utm.findIndexOfLargest(sMM[m], 0, utm.M);
				ss[i][m] = sMM[m][index];
				ssIndex[i][m] = index;
				sMM[m][index] = -1;
			}
		}
		
		//predicting ratings of movies rated by user
		for(int uid:utm.userListTrain){
			float fz = 0,fm = 0;
			for(int m1=0;m1<utm.M;m1++){
				for(int i = 0; i < S; i++){
					if(ss[i][m1]==0 || !utm.allMovies[ssIndex[i][m1]].users.containsKey(uid))
						continue;
					fz += ss[i][m1]*utm.allMovies[ssIndex[i][m1]].users.get(uid);
					fm += ss[i][m1];
				}
				preUMRating[utm.userListTrain.indexOf(uid)][m1] = fz/fm;
			}
		}
		System.out.println("preUMRating completed!");
		
//		//predicting ratings of movies rated by groups
//		for (int g = 0; g < utm.G; g++) {
//			float sumOfNum = 0;
//			for (int n : utm.allGroups[g].users.values())
//				sumOfNum += n;
//			for (int m = 0; m < utm.M; m++) {
//				float preAllGMRating = (policy == UtmRwr_Model.Policy.lm) ? Integer.MAX_VALUE : 0;
//				for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
//					switch (policy) {// change
//					case wtd:
//						preAllGMRating += user.getValue()
//								/ sumOfNum
//								* preUMRating[utm.userListTrain.indexOf(user
//										.getKey())][m];
//						break;
//					case lm:
//						preAllGMRating = Math.min(preAllGMRating,
//								preUMRating[utm.userListTrain.indexOf(user
//										.getKey())][m]);
//						break;
//					case avg:
//						preAllGMRating += preUMRating[utm.userListTrain
//								.indexOf(user.getKey())][m];
//						break;
//					}
//				}
//				if (policy == UtmRwr_Model.Policy.avg)
//					preAllGMRating /= utm.allGroups[g].users.size();
//				preGMRating[g][m] = preAllGMRating;
//			}
//		}
//		System.out.println("preGMRating completed!");
		
		try {
//			UtmRwr_Model.matrixToFile(ss, "./"+UtmRwr_Model.Model.item_pre+"/"+policy+"/ss_result.csv");
//			UtmRwr_Model.matrixToFile(preUMRating,"./"+UtmRwr_Model.Model.item_pre+"/"+policy+"/preUMRating_result.csv");
//			UtmRwr_Model.matrixToFile(preGMRating,"./"+UtmRwr_Model.Model.item_pre+"/"+policy+"/preGMRating_result.csv");
			UtmRwr_Model.matrixToFile(ss, "./"+UtmRwr_Model.Model.gui+"/"+policy+"/ss_result.csv");
			UtmRwr_Model.matrixToFile(preUMRating,"./"+UtmRwr_Model.Model.gui+"/"+policy+"/preUMRating_result.csv");
			UtmRwr_Model.matrixToFile(preGMRating,"./"+UtmRwr_Model.Model.gui+"/"+policy+"/preGMRating_result.csv");
		} catch (Exception e) {
			System.out.println("error in matrixToFile");
			e.printStackTrace();
		} 
	}
	
	public void userBasedModel(UtmRwr_Model.Policy policy){
		System.out.println("user based model");
		// similarity between users
		for (int uid1:utm.userListTrain) {
			int u1 = utm.userListTrain.indexOf(uid1);
			sUU[u1][u1] = 1;
			for (int uid2:utm.userListTrain) {
				int u2 = utm.userListTrain.indexOf(uid2);
				float fz = 0, fm1 = 0, fm2 = 0;
				int numOfCommonMovies = 0;
				for (int m = 0; m < utm.M; m++) {
					if (!utm.allMovies[m].users.containsKey(uid1) || 
						!utm.allMovies[m].users.containsKey(uid2))
						continue;
					numOfCommonMovies++;
					fz += (utm.allMovies[m].users.get(uid1) - calUMAvgRating[u1])
						* (utm.allMovies[m].users.get(uid2) - calUMAvgRating[u2]);
					fm1 += Math.pow(utm.allMovies[m].users.get(uid1) - calUMAvgRating[u1], 2);
					fm2 += Math.pow(utm.allMovies[m].users.get(uid2) - calUMAvgRating[u2], 2);
				}
				sUU[u1][u2] = (float)((numOfCommonMovies < 3 || fm1==0 || fm2==0) ? 0 : fz/(Math.sqrt(fm1) * Math.sqrt(fm2)));
				sUU[u2][u1] = sUU[u1][u2];
			}
		}
		System.out.println("sUU completed!");
		
		//3.13 update
		S = utm.U;
		ss = new float[S][];
		ssIndex = new int[S][];
		for (int i = 0; i < S; i++) {
			ss[i] = new float[utm.U];
			ssIndex[i] = new int[utm.U];
			for (int u = 0; u < utm.U; u++) {
				int index = utm.findIndexOfLargest(sUU[u], 0, utm.U);
				ss[i][u] = sUU[u][index];
				ssIndex[i][u] = index;
				sUU[u][index] = -1;
			}
		}
		System.out.println("ss completed!");
		
		//predicting ratings of movies rated by users
		for(int u1=0;u1<utm.U;u1++){
			for(int m=0;m<utm.M;m++){
				float fz = 0,fm = 0;
				for(int i = 0; i < S; i++){
					if(ss[i][u1]==0 || !utm.allMovies[m].users.containsKey(utm.allUsers[ssIndex[i][u1]]))
						continue;
					fz += ss[i][u1]*(utm.allMovies[m].users.get(utm.allUsers[ssIndex[i][u1]])-calUMAvgRating[ssIndex[i][u1]]);
					fm += Math.abs(ss[i][u1]);
				}
				preUMRating[u1][m] = (fm==0)?calUMAvgRating[u1]:(calUMAvgRating[u1] + fz/fm); // ??????
			}
		}
		System.out.println("preUMRating completed!");
		
//		//predicting ratings of movies rated by groups
//		for (int g = 0; g < utm.G; g++) {
//			float sumOfNum = 0;
//			for (int n : utm.allGroups[g].users.values()) 
//				sumOfNum += n;
//			for (int m = 0; m < utm.M; m++) {
//				float preAllGMRating = (policy == UtmRwr_Model.Policy.lm) ? Integer.MAX_VALUE : 0;
//				for (Entry<Integer, Integer> user : utm.allGroups[g].users.entrySet()) {
//					switch (policy) {// change
//					case wtd:
//						preAllGMRating += user.getValue() / sumOfNum
//								* preUMRating[utm.userListTrain.indexOf(user.getKey())][m];
//						break;
//					case lm:
//						preAllGMRating = Math.min(preAllGMRating,
//								preUMRating[utm.userListTrain.indexOf(user.getKey())][m]);
//						break;
//					case avg:
//						preAllGMRating += preUMRating[utm.userListTrain.indexOf(user.getKey())][m];
//						break;
//					}
//				}
//				if (policy == UtmRwr_Model.Policy.avg)
//					preAllGMRating /= utm.allGroups[g].users.size();
//				preGMRating[g][m] = preAllGMRating;
//			}
//		}
//		System.out.println("preGMRating completed!");
		
		try {
			UtmRwr_Model.matrixToFile(ss, "./"+UtmRwr_Model.Model.user+"/"+policy+"/ss_result.csv");
			UtmRwr_Model.matrixToFile(preUMRating,"./"+UtmRwr_Model.Model.user+"/"+policy+"/preUMRating_result.csv");
			UtmRwr_Model.matrixToFile(preGMRating,"./"+UtmRwr_Model.Model.user+"/"+policy+"/preGMRating_result.csv");
		} catch (Exception e) {
			System.out.println("error in matrixToFile");
			e.printStackTrace();
		} 
	}
	
	public void groupBasedModel(UtmRwr_Model.Policy policy) {	
		System.out.println("group based model");
		//similarity between groups
		for(int g1 = 0;g1<utm.G;g1++){
			sGG[g1][g1] = 1;
			for(int g2=g1+1;g2<utm.G;g2++){
				float fz = 0,fm1 = 0,fm2 = 0;
				int numOfCommonMovies=0;
				for(int m=0;m<utm.M;m++){
					if(calGMRating[g1][m]==-1 || calGMRating[g2][m]==-1)
						continue;
					numOfCommonMovies++;
					fz += (calGMRating[g1][m]-calGMAvgRating[g1])*(calGMRating[g2][m]-calGMAvgRating[g2]);
					fm1 += Math.pow(calGMRating[g1][m]-calGMAvgRating[g1], 2);
					fm2 += Math.pow(calGMRating[g2][m]-calGMAvgRating[g2], 2);
				}
				sGG[g1][g2] = (float)((numOfCommonMovies<3)?0:fz/(Math.sqrt(fm1)*Math.sqrt(fm2)));
				sGG[g2][g1] = sGG[g1][g2];
			}
		}
		System.out.println("sGG completed!");
		
		//3.13 update
		S = 270;
		ss = new float[S][];
		ssIndex = new int[S][];
		for (int i = 0; i < S; i++) {
			ss[i] = new float[utm.G];
			ssIndex[i] = new int[utm.G];
			for (int g = 0; g < utm.G; g++) {
				int index = utm.findIndexOfLargest(sGG[g], 0, utm.G);
				ss[i][g] = sGG[g][index];
				ssIndex[i][g] = index;
				sGG[g][index] = -1;
			}
		}
		
		//predicting rating of movies by groups
		for(int g1=0;g1<utm.G;g1++){
			float fz = 0,fm = 0;
			for(int m=0;m<utm.M;m++){
				for(int i = 0; i < S; i++){
					if(ss[i][g1] == 0 || calGMRating[ssIndex[i][g1]][m]==-1)
						continue;
					fz += ss[i][g1]*(calGMRating[ssIndex[i][g1]][m]-calGMAvgRating[ssIndex[i][g1]]);
					fm += Math.abs(ss[i][g1]);
				}
				preGMRating[g1][m] = calGMAvgRating[g1] + fz/fm;
			}
		}
		System.out.println("preGMRating completed!");
		
		try {
			String base = "./"+UtmRwr_Model.Model.group+"/"+policy+"/";
			UtmRwr_Model.matrixToFile(ss, base+"ss_result.csv");
			UtmRwr_Model.matrixToFile(calGMRating,base+"calGMRating_result.csv");
			UtmRwr_Model.matrixToFile(preGMRating,base+"preGMRating_result.csv");
		} catch (Exception e) {
			System.out.println("error in matrixToFile");
			e.printStackTrace();
		} 
	}
	
	
	/**
	 * 计算mae，auc，pcs,map
	 * @throws SQLException 
	 */
	public void maeAucPcsMapRecallUser(UtmRwr_Model.Model model,UtmRwr_Model.Policy policy) throws SQLException{
		
		utm.redirect(model,policy);
		
		try {
			Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序

			System.out.println("Success loading Mysql Driver!");
		} catch (Exception e) {
			System.out.print("Error loading Mysql Driver!");
			e.printStackTrace();
		}
		
		// 连接URL为 jdbc:mysql//服务器地址/数据库名 ，后面的2个参数分别是登陆用户名和密码
		utm.connect = DriverManager.getConnection(
			"jdbc:mysql://localhost:3306/rs_train0325_group", "root", "040016");
		
		System.out.println("Success connect Mysql server!");

		utm.stmt = utm.connect.createStatement();
		int mid;
		
		// AUC
		float result = 0;
		for (Integer testUser : utm.allUsersCheck) {
			utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
			try 
			{			
				// movie,movie-word
				ResultSet mrs = utm.stmt.executeQuery("select distinct movieid from user_movie where userid =" + testUser);
				while (mrs.next()) {
					mid = mrs.getInt("movieid");
					utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
				}

			} catch (Exception e) {
				System.out.print("get data error!");
				e.printStackTrace();
			}
			
			float rank = 0, pos = 0, neg = 0;
			
			Set<Integer> ratedMovies = new HashSet<Integer>();
			for (Movie testMovie : utm.movieListCheck.values()) {
					if (testMovie.users.containsKey(testUser)) {
						ratedMovies.add(testMovie.mid);
//						rank += rank(indexOfGroup(testGroup.gid),indexOfMovie(testMovie.mid));
						rank += rank_preUMRating(utm.indexOfUser(testUser),utm.indexOfMovie(testMovie.mid));
					}
			}
			
			pos = ratedMovies.size();
			int train_rated = utm.trainRatedMovieByGroup.size();
			neg = utm.M - pos - train_rated;
			result += (rank - pos * (pos + 1) / 2) / (pos * neg);
		}
		result /= utm.UT;
		System.out.println("AUC: " + result);

		//MAP
		float map = 0;
		for(Integer testUser : utm.allUsersCheck){
			
			utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
			try 
			{			
				// movie,movie-word
				ResultSet mrs = utm.stmt.executeQuery("select distinct movieid from user_movie where userid =" + testUser);
				while (mrs.next()) {
					mid = mrs.getInt("movieid");
					utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
				}

			} catch (Exception e) {
				System.out.print("get data error!");
				e.printStackTrace();
			}
			
			Set<Integer> ratedMovies = new HashSet<Integer>();
			for(Movie testMovie:utm.movieListCheck.values()){
					if(testMovie.users.containsKey(testUser)){
						ratedMovies.add(testMovie.mid);
					}
			}
			float count = 1,rank=0,value = 0;
//			for(int ratedMovieId:ratedMovies){
//				//old
////				rank = MT-rank(indexOfGroup(testGroup.gid),indexOfMovie(ratedMovieId))+1;
//				
//				rank = rank_rev(indexOfGroup(testGroup.gid),indexOfMovie(ratedMovieId));
////				rank = rank_preGMRating_rev(indexOfGroup(testGroup.gid),indexOfMovie(ratedMovieId));
//				value += count++/rank;
//			}
//			value /= ratedMovies.size();
//			map += value;
//			float value = 0;
//			int rank = 0;
//			ArrayList<Integer> tmp = new ArrayList<Integer>();
			for(int ratedMovieId:ratedMovies){
//				rank = utm.MT-rank(utm.indexOfGroup(testGroup.gid),utm.indexOfMovie(ratedMovieId))+1;
				rank = rank_preUMRating_rev(utm.indexOfUser(testUser),utm.indexOfMovie(ratedMovieId));
//				tmp.add(rank);
				value += count++/rank;
			}
			
//			Collections.sort(tmp);
//			Collections.sort(tmp,Collections.reverseOrder());
			
//			int rank_cnt = 1;
//			for(Integer rank_val : tmp)
//			{
//				value += rank_cnt++ * 1.0 / rank_val;
//			}
			
			value /= ratedMovies.size();
			map += value;
		}
		map /= utm.UT;
		System.out.println("map: " + map);
		
//		//precision_new & recall (k=20,40,60,...,600)
//		int[] movies = new int[M];//保存mid
//		float[] ratings = new float[M];
//		int[] maxMovies;
		for(int count=5;count<=200;count+=5){
			float pcs = 0, recall = 0;
//			maxMovies = new int[count];
			for(Integer testUser : utm.allUsersCheck){
				int[] movies = new int[utm.M];//保存mid
				float[] ratings = new float[utm.M];
				int[] maxMovies;
				maxMovies = new int[count];
				utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
				try 
				{			
					// movie,movie-word
					ResultSet mrs = utm.stmt.executeQuery("select movieid from movie where movieid not in (select distinct movieid from user_movie where userid = " +testUser + " )");
					while (mrs.next()) {
						mid = mrs.getInt("movieid");
						utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
					}

				} catch (Exception e) {
					System.out.print("get data error!");
					e.printStackTrace();
				}
				
				int i=0;
//				for(Movie testMovie:movieListCheck.values()){
				for(Movie testMovie:utm.trainRatedMovieByGroup.values()){
					movies[i] = testMovie.mid;
					ratings[i++] = preUMRating[utm.indexOfUser(testUser)][utm.indexOfMovie(testMovie.mid)];
//					ratings[i++] = ss[indexOfMovie(testMovie.mid)][indexOfGroup(testGroup.gid)];
				}
				int n=0,num=0;
				for(i=0;i<count;i++){
					int index = utm.findIndexOfLargest(ratings, 0, ratings.length);
					maxMovies[i] = movies[index];
					ratings[index] = -1;
						if(num==0){
							for(Movie mv:utm.movieListCheck.values()){
								if(mv.users.containsKey(testUser))
									num++;
							}
						}
						if(utm.movieListCheck.containsKey(maxMovies[i]) && utm.movieListCheck.get(maxMovies[i]).users.containsKey(testUser)){
							n++;
						}
				}
				pcs += (float)n/(float)count;
				recall += (float)n/(float)num;				
			}
			pcs /= utm.UT;
			recall /= utm.UT;
			System.out.println("k="+count+": precision="+pcs+" recall="+recall);
			try {
				utm.printVal(model,policy,pcs,"precision_val.txt");
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			try {
				utm.printVal(model,policy,recall,"recall_val.txt");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		System.setOut(utm.out);
	}
	
	
	private int rank_preUMRating(int u, int m) {
		int x = 1;
		int cnt = 0;
		for (int curM=0;curM<utm.M;curM++) {
//			if (!trainRatedMovieByGroup.containsKey(allMovies[curM].mid) && preGMRating[g][curM] < preGMRating[g][m])
			if (!utm.trainRatedMovieByGroup.containsKey(utm.allMovies[curM].mid))
			{
				++cnt;
				if(preUMRating[u][curM] < preUMRating[u][m])
				{
					++x;
				}
//				if(ss[curM][g]<ss[m][g])
//				{
//					++x;
//				}
			}

		}
		
		return x;
	}
	
	
	private int rank_preUMRating_rev(int u, int m) {
		int x = 1;
		int cnt = 0;
		for (int curM=0;curM<utm.M;curM++) {
//			if (!trainRatedMovieByGroup.containsKey(allMovies[curM].mid) && preGMRating[g][curM] < preGMRating[g][m])
			if (!utm.trainRatedMovieByGroup.containsKey(utm.allMovies[curM].mid))
			{
				++cnt;
				if(preUMRating[u][curM] > preUMRating[u][m])
				{
					++x;
				}
//				if(ss[curM][g]<ss[m][g])
//				{
//					++x;
//				}
			}

		}
		
		return x;
	}
	
	/**
	 * ����mae��auc��pcs
	 * @throws SQLException 
	 */
	private void maeAucPcsMapRecall(UtmRwr_Model.Model model,UtmRwr_Model.Policy policy) throws SQLException{
		
		utm.redirect(model,policy);
		try {
			Class.forName("com.mysql.jdbc.Driver"); // 加载MYSQL JDBC驱动程序

			System.out.println("Success loading Mysql Driver!");
		} catch (Exception e) {
			System.out.print("Error loading Mysql Driver!");
			e.printStackTrace();
		}
		
//		utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
		
		// 连接URL为 jdbc:mysql//服务器地址/数据库名 ，后面的2个参数分别是登陆用户名和密码
		utm.connect = DriverManager.getConnection(
			"jdbc:mysql://localhost:3306/rs_train0325_group", "root", "040016");
		System.out.println("Success connect Mysql server!");

		utm.stmt = utm.connect.createStatement();
		int mid;
		
//		// MAE
//		float totalmae = 0;
//		for (Group testGroup : utm.groupListCheck.values()) {
//			float mae = 0;
//			for (Movie testMovie : utm.movieListCheck.values()) {
//				float i = preGMRating[utm.indexOfGroup(testGroup.gid)][utm.indexOfMovie(testMovie.mid)];
//				if (utm.test_gmRating.get(testGroup.gid).containsKey(testMovie.mid))
//					i -= utm.test_gmRating.get(testGroup.gid).get(testMovie.mid);
//				mae += Math.abs(i);
//			}
//			mae /= utm.test_gmRating.get(testGroup.gid).size();
//			totalmae += mae;
//		}
//		totalmae /= utm.GT;
//		System.out.println("mae: " + totalmae);

		// AUC
		float result = 0;
		for (Group testGroup:utm.groupListCheck.values()) {
			utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
			try 
			{			
				// movie,movie-word
				ResultSet mrs = utm.stmt.executeQuery("select distinct movieid from user_movie where userid in (SELECT userid FROM household_user WHERE householdid =" +testGroup.gid + " )");
				while (mrs.next()) {
					mid = mrs.getInt("movieid");
					utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
				}

			} catch (Exception e) {
				System.out.print("get data error!");
				e.printStackTrace();
			}
			
			float rank = 0,pos=0,neg=0;
			
			Set<Integer> ratedMovies = new HashSet<Integer>();
			for (Movie testMovie : utm.movieListCheck.values()) {
				for(int uid:testGroup.users.keySet()){
					if(testMovie.users.containsKey(uid)){
						ratedMovies.add(testMovie.mid);
//						rank += rank(utm.indexOfGroup(testGroup.gid),utm.indexOfMovie(testMovie.mid));
						rank += rank_preGMRating(utm.indexOfGroup(testGroup.gid),utm.indexOfMovie(testMovie.mid));
						break;
					}
				}
			}
			pos = ratedMovies.size();
//			neg = utm.MT - pos;
			int train_rated = utm.trainRatedMovieByGroup.size();
			neg = utm.M - pos - train_rated;
			result += (rank - pos * (pos + 1) / 2) / (pos * neg);
		}
		result /= utm.GT;
		System.out.println("AUC: " + result);

//		//precision
//		float totalPcs = 0;
//		for (Group testGroup : utm.groupListCheck.values()) {
//			float pcs = 0;
//			for (Movie testMovie : utm.movieListCheck.values()) {
//				if(!utm.test_gmRating.get(testGroup.gid).containsKey(testMovie.mid))
//					continue;
//				float dif = preGMRating[utm.indexOfGroup(testGroup.gid)][utm.indexOfMovie(testMovie.mid)] - utm.test_gmRating.get(testGroup.gid).get(testMovie.mid);
//				float fm = Math.max(Math.abs(utm.max-utm.test_gmRating.get(testGroup.gid).get(testMovie.mid)),
//									  Math.abs(utm.min-utm.test_gmRating.get(testGroup.gid).get(testMovie.mid)));
//				pcs += Math.abs(dif)/fm;
//			}
//			totalPcs += 1-pcs/utm.numOfMoviesRatedByGroup(testGroup.gid);
//		}
//		totalPcs /= utm.GT;
//		System.out.println("precision: " + totalPcs);
		
		//MAP
		double map = 0;
		for(Group testGroup:utm.groupListCheck.values()){
			
			utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
			try 
			{			
				// movie,movie-word
				ResultSet mrs = utm.stmt.executeQuery("select distinct movieid from user_movie where userid in (SELECT userid FROM household_user WHERE householdid =" +testGroup.gid + " )");
				while (mrs.next()) {
					mid = mrs.getInt("movieid");
					utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
				}

			} catch (Exception e) {
				System.out.print("get data error!");
				e.printStackTrace();
			}
			
			Set<Integer> ratedMovies = new HashSet<Integer>();
			for(Movie testMovie:utm.movieListCheck.values()){
				for(int uid:testGroup.users.keySet()){
					if(testMovie.users.containsKey(uid)){
						ratedMovies.add(testMovie.mid);
						break;
					}
				}
			}
			float value = 0;
			float rank = 0;
			float count = 1;
//			ArrayList<Integer> tmp = new ArrayList<Integer>();
			for(int ratedMovieId:ratedMovies){
//				rank = utm.MT-rank(utm.indexOfGroup(testGroup.gid),utm.indexOfMovie(ratedMovieId))+1;
				rank = rank_preGMRating_rev(utm.indexOfGroup(testGroup.gid),utm.indexOfMovie(ratedMovieId));
//				tmp.add(rank);
				value += count++/rank;
			}
			
//			Collections.sort(tmp);
//			Collections.sort(tmp,Collections.reverseOrder());
			
//			int rank_cnt = 1;
//			for(Integer rank_val : tmp)
//			{
//				value += rank_cnt++ * 1.0 / rank_val;
//			}
			
			value /= ratedMovies.size();
			map += value;
		}
		map /= utm.GT;
		System.out.println("map: " + map);
		
		//precision_new & recall (k=5,10,15,...,95,100)
//		int[] movies = new int[utm.MT];//保存mid
//		float[] ratings = new float[utm.MT];
//		int[] maxMovies;
		for(int count=5;count<=200;count+=5){
			float pcs = 0, recall = 0;
//			maxMovies = new int[count];
			for(Group testGroup:utm.groupListCheck.values()){
				
				int[] movies = new int[utm.M];//保存mid
				float[] ratings = new float[utm.M];
				int[] maxMovies;
				maxMovies = new int[count];
				utm.trainRatedMovieByGroup = new HashMap<Integer,Movie>();
				try 
				{			
					// movie,movie-word
					ResultSet mrs = utm.stmt.executeQuery("select movieid from movie where movieid not in (select distinct movieid from user_movie where userid in (SELECT userid FROM household_user WHERE householdid = " +testGroup.gid + " ))");
					while (mrs.next()) {
						mid = mrs.getInt("movieid");
						utm.trainRatedMovieByGroup.put(mid, new Movie(mid)); // ??????????????
					}

				} catch (Exception e) {
					System.out.print("get data error!");
					e.printStackTrace();
				}
				
				int i=0;
				for(Movie testMovie:utm.movieListCheck.values()){
					movies[i] = testMovie.mid;
					ratings[i++] = preGMRating[utm.indexOfGroup(testGroup.gid)][utm.indexOfMovie(testMovie.mid)];
				}
				int n=0,num=0;
				for(i=0;i<count;i++){
					int index = utm.findIndexOfLargest(ratings, 0, ratings.length);
					maxMovies[i] = movies[index];
					ratings[index] = -1;
					for(int uid:testGroup.users.keySet()){
						if(num==0){
							for(Movie mv:utm.movieListCheck.values()){
								if(mv.users.containsKey(uid))
									num++;
							}
						}
						if(utm.movieListCheck.containsKey(maxMovies[i]) && utm.movieListCheck.get(maxMovies[i]).users.containsKey(uid)){
							n++;
							break;
						}
					}
				}
				pcs += (float)n/(float)count;
				recall += (float)n/(float)num;				
			}
			pcs /= utm.GT;
			recall /= utm.GT;
			System.out.println("k="+count+": precision="+pcs+" recall="+recall);
			try {
				utm.printVal(model,policy,pcs,"precision_val.txt");
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			try {
				utm.printVal(model,policy,recall,"recall_val.txt");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	// m在g中的rating从小到大的排名(最小为1)
	private int rank(int g, int m) {
		int x = 1;
		for (int curM=0;curM<utm.M;curM++) {
			if (utm.movieListCheck.containsKey(utm.allMovies[curM].mid) && preGMRating[g][curM] < preGMRating[g][m])
				x++;
		}
		return x;
	}
	
	private int rank_preGMRating(int g, int m) {
		int x = 1;
		int cnt = 0;
		for (int curM=0;curM<utm.M;curM++) {
//			if (!trainRatedMovieByGroup.containsKey(allMovies[curM].mid) && preGMRating[g][curM] < preGMRating[g][m])
			if (!utm.trainRatedMovieByGroup.containsKey(utm.allMovies[curM].mid))
			{
				++cnt;
				if(preGMRating[g][curM] < preGMRating[g][m])
				{
					++x;
				}
//				if(ss[curM][g]<ss[m][g])
//				{
//					++x;
//				}
			}

		}
		
		return x;
	}

	private int rank_preGMRating_rev(int g, int m) {
		int x = 1;
		int cnt = 0;
		for (int curM=0;curM<utm.M;curM++) {
//			if (!trainRatedMovieByGroup.containsKey(allMovies[curM].mid) && preGMRating[g][curM] < preGMRating[g][m])
			if (!utm.trainRatedMovieByGroup.containsKey(utm.allMovies[curM].mid))
			{
				++cnt;
				if(preGMRating[g][curM] > preGMRating[g][m])
				{
					++x;
				}
//				if(ss[curM][g]<ss[m][g])
//				{
//					++x;
//				}
			}

		}
		
		return x;
	}
	
}



